package fi.jamk.ourcookingapp.backend.architecture.manager;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import fi.jamk.ourcookingapp.backend.MyTools;
import fi.jamk.ourcookingapp.backend.architecture.interfaces.IReceiptManager;
import fi.jamk.ourcookingapp.backend.architecture.json.WebService;
import fi.jamk.ourcookingapp.backend.exceptions.NoReceiptException;
import fi.jamk.ourcookingapp.backend.model.Ingredient;
import fi.jamk.ourcookingapp.backend.model.Rating;
import fi.jamk.ourcookingapp.backend.model.Receipt;
import fi.jamk.ourcookingapp.backend.model.Step;
import fi.jamk.ourcookingapp.backend.model.User;

public class ReceiptManager implements IReceiptManager {

	private HashMap<String, Object> filter;
	
	private HashMap<String, String> options;
	
	public static final String INGREDIENT = "ingredient";
	public static final String USER_LOGIN_NAME = "loginName";
	public static final String NAME = "name";
	public static final String ID = "id";
	public static final String USER_ID = "user_id";
	public static final String LIMIT_KEY = "LIMIT";
	
	public static final int LIMIT = 7;
	
	public static final String ASCDESC = "ascdesc";
	public static final String ORDER_BY = "ORDER BY";
	
	public static final String ORDER_RATING = "rating";
	public static final String ORDER_DATE = "date";
	public static final String ORDER_COUNT_CLICKS = "countClicks";
	public static final String ORDER_DURATION = "duration";
	
	public static final String ASCENDING = "ASC";
	public static final String DESCENDING = "DESC";

	private static final String CONTROLLER = "receipt";

	
	
	@SuppressLint("SimpleDateFormat")
	private SimpleDateFormat sdfToDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public ReceiptManager() {
		initFilter();
		initOption();
	}

	private void initOption() {
		options = new HashMap<String, String>();
		options.put(ASCDESC, DESCENDING);
		options.put(ORDER_BY, ORDER_DATE);
	}

	private void initFilter() {
		filter = new HashMap<String, Object>();
		filter.put(INGREDIENT, null);
		filter.put(USER_LOGIN_NAME, null);
		filter.put(NAME, null);
		filter.put(ID, null);
		filter.put(USER_ID, null);
		filter.put(LIMIT_KEY, null);
	}
	
	public void setFilter(String key, Object value){
		filter.put(key, value);
	}
	
	public void setOption(String key, String value){
		options.put(key, value);
	}
	
	@Override
	public boolean deleteReceipt(Receipt receipt) throws InterruptedException, ExecutionException, JSONException {
		String getData = "receipt_id=>" + receipt.getID();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "delete");
		boolean deleted = JSONresult.get().getBoolean("delete");
        return deleted;
	}

	@Override
	public Receipt updateReceipt(Receipt receipt, boolean clicks) throws InterruptedException, ExecutionException, JSONException {
		String getData = "receipt_id=>"+receipt.getID()+"&name=>"+receipt.getName()+"&description=>"+receipt.getDescription()+"&effort=>"+receipt.getEffort()+"&duration=>"+receipt.getDuration()+"&countClicks=>"+receipt.getCountClicks();;
		if(!clicks){
			for(Ingredient ing : receipt.getLstIngredient())
	        {
	            getData += "&ingredients[]=>"+ing.getID();
	        }
			for(Ingredient ing : receipt.getLstIngredient())
	        {
	            getData += "&amount[]=>"+ing.getAmount();
	        }
			createSteps(receipt.getID(), receipt.getLstStep());
		}
		
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "update");
		boolean res = JSONresult.get().getBoolean("receipt");
		if(!res){
			// TODO
		}
		return receipt;
	}

	@Override
	public Receipt createReceipt(Receipt receipt) throws InterruptedException, ExecutionException, JSONException {
		String getData = "user_id=>"+receipt.getUser().getID()+"&name=>"+receipt.getName()+"&description=>"+receipt.getDescription()+"&effort=>"+receipt.getEffort()+"&duration=>"+receipt.getDuration();
		for(Ingredient ing : receipt.getLstIngredient())
        {
            getData += "&ingredients[]=>"+ing.getID();
        }
		for(Ingredient ing : receipt.getLstIngredient())
        {
            getData += "&amount[]=>"+ing.getAmount();
        }
        AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "create");
		int receiptID = JSONresult.get().getInt("receipt");
		receipt.setID(receiptID);
		createSteps(receipt.getID(), receipt.getLstStep());
		return receipt;
	}

	private void createSteps(int receiptID, List<Step> lstStep) throws InterruptedException, ExecutionException, JSONException {
		String numbersdesc = "";
		for (int i = 0; i < lstStep.size(); i++) {
			numbersdesc += "&numbers[]=>" + lstStep.get(i).getNumber() + "&descriptions[]=>" + lstStep.get(i).getDescription();
		}
		String getData = "receipt_id=>" + receiptID + numbersdesc;
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "createSteps");
		boolean added = JSONresult.get().getBoolean("step");
		if(!added){
			// TODO 
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Receipt> filter(boolean count) throws InterruptedException, ExecutionException, NoReceiptException {
		List<Receipt> result = new ArrayList<Receipt>();
		String join = "JOIN user ON user.id = receipt.user_id ";
		List<String> wheres = new ArrayList<String>();
		String sort = ORDER_BY + " " + (String)options.get(ORDER_BY) + " " + (String)options.get(ASCDESC);
		
		if(filter.get(USER_LOGIN_NAME) != null){
			wheres.add(" user.loginName LIKE '%" + (String)filter.get(USER_LOGIN_NAME) + "%' ");
		}
		if(filter.get(USER_ID) != null){
			wheres.add(" user.id=" + filter.get(USER_ID));
		}
		if(filter.get(INGREDIENT) != null){
			List<String> ingredients = (ArrayList<String>) filter.get(INGREDIENT);
			String in = "IN(" + MyTools.implode(",", ingredients) + ")";
			join += "JOIN receipt_ingredient ON receipt_ingredient.ingredient_id " + in;
			wheres.add(" receipt_ingredient.receipt_id = receipt.id");
		}
		if(filter.get(NAME) != null){
			wheres.add(" receipt.name LIKE '%" + (String)filter.get(NAME) + "%' ");
		}
		if(filter.get(ID) != null){
			wheres.add("id = " + (String)filter.get(ID));
		}
		wheres.add(" deleted = false");
		
		String whereString = "";
		for (String string : wheres) {
			whereString += "&where[]=>" + string;
		}
		
		if(!count){
			sort += " LIMIT "+filter.get(LIMIT_KEY)+", " + LIMIT;
		}
		String getData = "join=>" + join + "&sort=>" + sort + whereString;
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "filter");
		try {
			JSONArray receipts = JSONresult.get().getJSONArray("receipts");
			for (int i=0;i < receipts.length();i++) {
				JSONObject JSONrec = receipts.getJSONObject(i);
				result.add(genReceipt(JSONrec));
			}
		} catch (Exception e) {
			try {
				JSONObject objRec = JSONresult.get().getJSONObject("receipts");
				result.add(genReceipt(objRec));
			} catch (JSONException e1) {
				throw new NoReceiptException();
			}
		}
		initFilter();
		
		return result;
	}
	
	/**
	 * Generates a receipt object by the JSONObect
	 * @param JSONrec
	 * @return Receipt 
	 * @throws JSONException
	 */
	private Receipt genReceipt(JSONObject JSONrec) throws JSONException{
		Receipt rec = new Receipt();
		rec.setID(JSONrec.getInt("id"));
		rec.setDuration(JSONrec.getInt("duration"));
		rec.setDescription(JSONrec.getString("description"));
		rec.setName(JSONrec.getString("name"));
		rec.setEffort(JSONrec.getString("effort"));
		rec.setRating(JSONrec.getDouble("rating"));
		rec.setCountClicks(JSONrec.getInt("countClicks"));
		rec.setUser(new User(JSONrec.getString("loginName"), JSONrec.getInt("user_id")));
		try {
			rec.setDate(sdfToDate.parse(JSONrec.getString("date")));
		} catch (ParseException e) {
		}
		return rec;
	}

	@Override
	public double rateReceipt(Receipt receipt, Rating rating) throws InterruptedException, ExecutionException, NumberFormatException, JSONException {
		String getData = "receipt_id=>" + receipt.getID() + "&user_id=>" + rating.getUser().getID() + "&amount=>" + rating.getAmount();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "rate");
		double rated = Double.parseDouble(JSONresult.get().getString("rate"));
		return rated;
	}

	@Override
	public List<Ingredient> getAllIngredients() throws JSONException, InterruptedException, ExecutionException {
		List<Ingredient> result = new ArrayList<Ingredient>();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute("", CONTROLLER, "getAllIngredients");
		JSONArray ingredients = JSONresult.get().getJSONArray("ingredients");
		for (int i=0;i < ingredients.length();i++) {
			JSONObject JSONing = ingredients.getJSONObject(i);
			result.add(genIngredient(JSONing));
		}
		return result;
	}

	/**
	 * Generates an ingredient by the given JSONObejct
	 * @param jSONing
	 * @return Ingredient
	 * @throws JSONException
	 */
	private Ingredient genIngredient(JSONObject jSONing) throws JSONException {
		Ingredient ing = new Ingredient(jSONing.getString("name"), jSONing.getString("typeOfAmount"));
		ing.setID(jSONing.getInt("id"));
		try{
			ing.setAmount(jSONing.getInt("amount"));
		} catch (Exception e){
		}
		return ing;
	}

	@Override
	public void addToFavourite(Receipt receipt, User user) throws JSONException, InterruptedException, ExecutionException {
		String getData = "user_id=>" + user.getID() + "&receipt_id=>" + receipt.getID();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "addToFavourite");
		boolean added = JSONresult.get().getBoolean("result");
		if(!added){
			// TODO
		}
	}
	
	@Override
	public List<Receipt> getFavourites(User user) throws JSONException, InterruptedException, ExecutionException{
		List<Receipt> result = new ArrayList<Receipt>();
		String getData = "user_id=>" + user.getID();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "favouriteReceipts");
		JSONArray receipts = JSONresult.get().getJSONArray("receipts");
		for (int i=0;i < receipts.length();i++) {
			JSONObject JSONrec = receipts.getJSONObject(i);
			result.add(genReceipt(JSONrec));
		}
		return result;
	}

	@Override
	public List<Ingredient> ingredientsByReceipt(Receipt receipt) throws JSONException, InterruptedException, ExecutionException {
		List<Ingredient> result = new ArrayList<Ingredient>();
		String getData = "receipt_id=>" + receipt.getID();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "getIngredients");
		JSONArray ingredients = JSONresult.get().getJSONArray("ingredients");
		for (int i=0;i < ingredients.length();i++) {
			JSONObject JSONing = ingredients.getJSONObject(i);
			result.add(genIngredient(JSONing));
		}
		return result;
	}

	@Override
	public List<Step> stepsByReceipt(Receipt receipt) throws JSONException, InterruptedException, ExecutionException {
		List<Step> result = new ArrayList<Step>();
		String getData = "receipt_id=>" + receipt.getID();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "getSteps");
		JSONArray ingredients = JSONresult.get().getJSONArray("step");
		for (int i=0;i < ingredients.length();i++) {
			JSONObject JSONing = ingredients.getJSONObject(i);
			result.add(new Step(Integer.parseInt(JSONing.getString("number")), JSONing.getString("description")));
		}
		return result;
	}

	@Override
	public void removeFromFavourite(Receipt receipt, User user) throws JSONException, InterruptedException, ExecutionException {
		String getData = "user_id=>" + user.getID() + "&receipt_id=>" + receipt.getID();
		AsyncTask<String, Void, JSONObject> JSONresult = new WebService().execute(getData, CONTROLLER, "removeFromFavourite");
		boolean added = JSONresult.get().getBoolean("result");
		if(!added){
			// TODO
		}
	}

}
